using System;

using FineCollection.Intf;




namespace FineCollection.Immutable
{
    /// <summary>
    /// Immutable set of exactly one item. 
    /// This item must be not null.
    /// </summary>
    /// <typeparam name="T">type of the item.</typeparam>
    public class ImmOrderOne<T> : ImmOne<T>, RRandomSet<T>
        where T: IComparable<T>
    {


        #region CONSTRUCTOR

        /// <summary>
        /// Trivial constructor.
        /// </summary>
        /// <param name="item">the single item (not null).</param>
        public ImmOrderOne(T item)
            : base (item)
        {}

        #endregion



        public T First
        {
            get { return item; }
        }

        public T Last
        {
            get { return item; }
        }


        public int FirstIndex
        {
            get { return 1; }
        }

        public int LastIndex
        {
            get { return 1; }
        }


        public T this[int index]
        {
            get
            {
                if (index == 1)
                    return item;
                else
                    throw new IndexOutOfBoundsException(index, 1, 1);
            }
        }


        /// <summary>
        /// Looks for the specified item, 
        /// or for the possible position where this item may be placed
        /// if this item is not in the collection.
        /// </summary>
        /// <param name="item">an item to look for.</param>
        /// <param name="found">true if found, false otherwise.</param>
        /// <param name="position">
        /// <ul>
        /// <li>if the item is found - the position of this item;</li>
        /// <li>if the item is not found and the set is not empty -
        ///        the position of the nearest item larger than the specified one;</li>
        /// <li>if all items of the set are less than the specified one - 
        ///        the <see cref="RRandomList{T}.LastIndex"/> + 1;</li>
        /// <li>if the set is empty - 
        ///        the <see cref="RRandomList{T}.FirstIndex"/>.</li>
        /// </ul>
        /// </param>
        public void Find(T item, out bool found, out int position)
        {
            if (item == null)
                throw new NullItemsException();

            int z = Math.Sign( item.CompareTo(this.item) );
            switch (z)
            {
                case 0:
                    found = true;
                    position = FirstIndex;
                    break;
                case -1:
                    found = false;
                    position = FirstIndex;
                    break;
                case +1:
                    found = false;
                    position = FirstIndex + 1;
                    break;
                default:
                    throw new InternalAlgorythmError(
                        "Math.Sign must return one of {-1,0,+1}.");
            }
        }


        /// <summary>
        /// Looks for the specified item.
        /// </summary>
        /// <param name="item">an item to look for, may be null.</param>
        /// <returns>index of the found item, 
        ///          or <see cref="int.MinValue"/> if not found.</returns>
        /// <remarks>
        /// When the specified item is null - 
        /// does nothing and returns <see cref="int.MinValue"/>.
        /// </remarks>
        public int IndexOf(T item)
        {
            if (item != null && this.item.Equals(item))
                return FirstIndex;
            else
                return int.MinValue;
        }


        new public ROrderIterator<T> TakeIterator()
        {
            return new OrderIteratorOfOne<T>(this);
        }



        internal class OrderIteratorOfOne<TT> : IteratorOfOne<TT>, ROrderIterator<TT>
            where TT: IComparable<TT>
        {
            public OrderIteratorOfOne(ImmOne<TT> one) 
                : base(one)
            {}

            public OrderIteratorOfOne(ImmOne<TT> one, sbyte state) 
                : base(one, state)
            {}


            public JumpResult Jump(TT item)
            {
                if (item == null)
                    throw new NullItemsException();

                int z;

                switch (state)
                {
                    case -1:
                        z = Math.Sign(item.CompareTo(base.one.item));
                        switch (z)
                        {
                            case -1:
                                state = 0;
                                return JumpResult.Over;
                            case 0:
                                state = 0;
                                return JumpResult.Exactly;
                            case +1:
                                state = +1;
                                return JumpResult.End;
                            default:
                                throw new InternalAlgorythmError("math.sign");
                        }
                    
                    case 0:
                        z = Math.Sign(item.CompareTo(base.one.item));
                        switch (z)
                        {
                            case -1:
                                return JumpResult.Before;
                            case 0:
                                return JumpResult.Exactly;
                            case +1:
                                state = +1;
                                return JumpResult.End;
                            default:
                                throw new InternalAlgorythmError("math.sign");
                        }
                       
                    case +1:
                        return JumpResult.End;

                    default:
                        throw new InternalAlgorythmError("math.sign");
                }
            }
        }
    }
}